#pragma once
#include <string>

using namespace std;

enum SyntacticType { CONSTANT, VARIABLE, PROCEDURE, 
					STMTLIST, ASSIGN, WHILE, IF, PLUS, 
					MINUS, TIMES, CALL, PROGRAM };
	
class DesignEntity{
private:
	SyntacticType type;
public:
	/** A virtual destructor that does nothing. 
	 *  This ensures the class is abstract.
	 */
	virtual ~DesignEntity() = 0;
	
	/** Initialises a DesignEntity of type SyntacticType t 
	 *  @param t the type of this DesignEntity object
	 */
	DesignEntity(SyntacticType t);

	/** Returns the type of this object
	 *  @return the enum type of this DesingEntity
	 */
	SyntacticType getType();
	
	/** Checks if this object is equal to the object passed in as argument
	 *  @param otherDE the object to which this object is to be compared to
	 *  @return true is equal, else false
	 */
	bool equal(DesignEntity* otherDE);
};

class Constant : public DesignEntity{
private:
	int value;
public:
	/** Initialises a Constant DesignEntity with value val 
	 *  @param val the value of this Constant
	 */
	Constant(int val);

	/** Returns the value of this Constant
	 *  @return an integer that is the value of this Constant
	 */
	int getValue();
};

class Variable : public DesignEntity{
private:
	int index;
public:
	/** Initialises a Variable DesignEntity with index index 
	 *  @param index the index of this Variable
	 */
	Variable(int index);

	/** Returns the index of this Variable
	 *  @return an integer that is the index of this Variable
	 */
	int getIndex();
};

class Procedure : public DesignEntity{
private:
	int index;
public:
	/** Initialises a Procedure DesignEntity with index index 
	 *  @param index the index of this Procedure
	 */
	Procedure(int index);

	/** Returns the index of this Procedure
	 *  @return an integer that is the index of this Procedure
	 */
	int getIndex();
};

class StmtList : public DesignEntity{
public:
	/** Initialises a StmtList DesignEntity 
	 */
	StmtList();
};

class Assign : public DesignEntity{
public:
	/** Initialises a Assign DesignEntity 
	 */
	Assign();
};

class While : public DesignEntity{
public:
	/** Initialises a While DesignEntity 
	 */
	While();
};

class If : public DesignEntity{
public:
	/** Initialises a If DesignEntity 
	 */
	If();
};

class Plus : public DesignEntity{
public:
	/** Initialises a Plus DesignEntity 
	 */
	Plus();
};

class Minus : public DesignEntity{
public:
	/** Initialises a Minus DesignEntity 
	 */
	Minus();
};

class Times : public DesignEntity{
public:
	/** Initialises a Times DesignEntity 
	 */
	Times();
};

class Call : public DesignEntity{
private:
	int procIndex;
public:
	/** Initialises a Call DesignEntity that calls Procedure procIndex 
	 *  @param procIndex the index of the Procedure called by this Call
	 */
	Call(int procIndex);

	/** Returns the index of the Procedure called by this Call
	 *  @return an integer that is the index of the Procedure called by this Call
	 */
	int getProcIndex();
};


class Program : public DesignEntity{
public:
	/** Initialises a Program DesignEntity 
	 */
	Program();
};